﻿using iot.Commons;
using iot.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using xktComm;
using xktComm.Common;

namespace iot.Protocol.Smz
{
    public class SimensS200Net : IPrototol
    {
        private xktComm.SiemensS7? SiemensS7 { get; set; }

        private bool connected = false;

        public bool Disconnect()
        {
            try
            {
                if (SiemensS7 != null) // Ensure SiemensS7 is not null before dereferencing
                {
                    SiemensS7.DisConnect();
                    connected = false;
                }
                return true;
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
        }

        bool IPrototol.Connect(PlcInfo plcInfo)
        {
            try
            {
                SiemensS7 = new xktComm.SiemensS7();
                SiemensS7.ConnectTimeOut = 5000;
                SiemensS7.ReceiveTimeOut = 5000;
                SiemensS7.MaxPDUSize = 240;
                SiemensS7.Connect(plcInfo.IP, CPU_Type.S7200, 0, 0);
                if (SiemensS7.tcpclient.Connected)
                {
                    connected = true;
                }
                return connected;
            }
            catch (Exception ex)
            {
                throw new Exception("连接失败", ex);
            }
        }

        object IPrototol.ReadData(PointInfo pointInfo,DataFormatEnum dataFormatEnum)
        {
            if (SiemensS7 == null) // Fix CS8602 by checking for null before dereferencing
            {
                throw new InvalidOperationException("SiemensS7 is not initialized.");
            }

            string? value = null; // Fix CS8600 by allowing value to be nullable
            string[] values = new string[] { };
            switch (pointInfo.pointType)
            {
                case nameof(DataTypeEnum.INT): // Fix CS0029 by comparing with string representation of the enum
                    value = SiemensS7.Read(StoreType.DataBlock, 1, 100, VarType.DInt, 10)?.ToString(); // Fix CS8600 by using null-conditional operator
                    values = value.Split(",") ?? Array.Empty<string>();  // Fix CS8602 by using null-coalescing operator
                    break; // Fix CS8070 by adding a break statement
                case nameof(DataTypeEnum.SHORT):
                    value = SiemensS7.Read(StoreType.DataBlock, 1, 100, VarType.Int, 10)?.ToString(); // Fix CS8600 by using null-conditional operator
                    values = value.Split(",") ?? Array.Empty<string>();  // Fix CS8602 by using null-coalescing operator
                    break; // Fix CS8070 by adding a break statement
                case nameof(DataTypeEnum.LONG):
                    value = SiemensS7.Read(StoreType.DataBlock, 1, 100, VarType.Long, 10)?.ToString(); // Fix CS8600 by using null-conditional operator
                    values = value.Split(",") ?? Array.Empty<string>();  // Fix CS8602 by using null-coalescing operator
                    break; // Fix CS8070 by adding a break statement
                case nameof(DataTypeEnum.ULONG):
                    value = SiemensS7.Read(StoreType.DataBlock, 1, 100, VarType.ULong, 10)?.ToString(); // Fix CS8600 by using null-conditional operator
                    values = value.Split(",") ?? Array.Empty<string>();  // Fix CS8602 by using null-coalescing operator
                    break; // Fix CS8070 by adding a break statement
                case nameof(DataTypeEnum.FLOAT):
                    value = SiemensS7.Read(StoreType.DataBlock, 1, 100, VarType.Real, 10)?.ToString(); // Fix CS8600 by using null-conditional operator
                    values = value.Split(",") ?? Array.Empty<string>();  // Fix CS8602 by using null-coalescing operator
                    break; // Fix CS8070 by adding a break statement
                case nameof(DataTypeEnum.DOUBLE):
                    value = SiemensS7.Read(StoreType.DataBlock, 1, 100, VarType.LReal, 10)?.ToString(); // Fix CS8600 by using null-conditional operator
                    values = value.Split(",") ?? Array.Empty<string>();  // Fix CS8602 by using null-coalescing operator
                    break; // Fix CS8070 by adding a break statement
                case nameof(DataTypeEnum.BOOL):
                    value = SiemensS7.Read(StoreType.DataBlock, 1, 100, VarType.Bit, 10)?.ToString(); // Fix CS8600 by using null-conditional operator
                    values = value.Split(",") ?? Array.Empty<string>();  // Fix CS8602 by using null-coalescing operator
                    break; // Fix CS8070 by adding a break statement
                default:
                    throw new NotSupportedException($"Unsupported point type: {pointInfo.pointType}");
            }

            if (value == null) // Handle the case where value is null
            {
                throw new InvalidOperationException("Read operation returned null.");
            }
            pointInfo.Value = value;
            pointInfo.Values = values;
            return value;
        }

        bool IPrototol.WriteData(PointInfo pointInfo, object d, DataTypeEnum dataTypeEnum)
        {
            try
            {
                if (SiemensS7 == null) // Fix CS8602 by checking for null before dereferencing
                {
                    throw new InvalidOperationException("SiemensS7 is not initialized.");
                }

                if (pointInfo == null || string.IsNullOrEmpty(pointInfo.Value)) // Additional null checks for pointInfo and its Value
                {
                    throw new ArgumentNullException(nameof(pointInfo), "PointInfo or its Value cannot be null.");
                }

                // Convert the object 'd' to a string before passing it to the Write method
                string dataAsString = d.ToString() ?? throw new ArgumentNullException(nameof(d), "Data cannot be null.");

                
                bool res = SiemensS7.Write(pointInfo.address, dataAsString);
                if (!res) // Handle potential failure of the Write operation
                {
                    throw new InvalidOperationException($"Write operation failed");
                }

                return res; // Indicate success
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
        }
    }
}
